package Hxw3DEngine.asset.parsers 
{
	/**
	 * Bson format file parser
	 * @author Lighter
	 */

	import flash.display.BitmapData;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	import org.serialization.bson.BSON;
	import Hxw3DEngine.asset.loader.LoaderDeferred;
	import org.serialization.bson.BSON;
	import Hxw3DEngine.asset.parsers.bson.Header;
	import Hxw3DEngine.asset.parsers.bson.CompressionMethod;
	import Hxw3DEngine.asset.parsers.bson.vo.*;
	import org.osflash.async.whenOneArray;
	import Hxw3DEngine.asset.parsers.bson.vo.BsonVO;
	
	public class BsonParser extends ParserBase 
	{
		public static const VERSION_MAJOR:uint =	0;
		public static const VERSION_MINOR:uint =	1;
		public static const BMDL_MAGIC:String = "BMDL";
		
		private static const ParserStep_Header:uint = 0;
		private static const ParserStep_Uncompress:uint = 1;
		private static const ParserStep_DecodeBson:uint = 2;
		private static const ParserStep_ParseChunks:uint = 3;
		private static const ParserStep_WaitingForTextures:uint = 4;
		private static const ParserStep_Done:uint = 5;
	
		private var _url:String;
		
		private var _parsedStep:uint;	// 当前的解析步骤
		private var _texturesFinished:Boolean = false;
		
		private var _header:Header;		// 文件头
		private var _lastData:ByteArray;// 数据
		
		private var _document:Object;	// 解析出的对象数据
		private var _documentVO:BsonVO;	// 解析出的VO数组
		private var _arrTexture:Array;	// 数据中包含的纹理数据
		private var _bitmapData:Array;	// 包含的位图数据
		
		public function BsonParser(url:String) 
		{
			_url = url;
		}
		
		override public function proceedParsing():Boolean 
		{
			if (!startedParsing) {
				startedParsing = true;
			}			
			while (hasTime()) {
				switch (_parsedStep) 
				{
					case ParserStep_Header:
						targetData.endian = Endian.LITTLE_ENDIAN;
						targetData.position = 0;
						_header = new Header(targetData);
						if (!_header.IsValid(BMDL_MAGIC, VERSION_MAJOR, VERSION_MINOR)) {
							error = new Error("Bson Header isn't valid. BMDL_MAGIC = " + BMDL_MAGIC + ",VERSION_MAJOR = " + VERSION_MAJOR + ",VERSION_MINOR = " + VERSION_MINOR);
							_parsedStep = ParserStep_Done;
							return true;
						}
						_parsedStep = ParserStep_Uncompress;
						break;
					case ParserStep_Uncompress:
						uncompress();
						_parsedStep = ParserStep_DecodeBson;
						break;
					case ParserStep_DecodeBson:
						_document = BSON.decode(_lastData);
						_parsedStep = ParserStep_ParseChunks;
						break;
					case ParserStep_ParseChunks:
						processChunks(_document);
						if (_arrTexture == null) {
							_parsedStep = ParserStep_Done;
							return true;
						}
						_parsedStep = ParserStep_WaitingForTextures;
						break;
					case ParserStep_WaitingForTextures:
						if (_texturesFinished) {
							_parsedStep = ParserStep_Done;
							return true;							
						}
						return false;
						break;
				}
			}
			return false;
		}
		
		private function uncompress():void{
			_lastData = new ByteArray();
			_lastData.endian = Endian.LITTLE_ENDIAN;

			targetData.readBytes(_lastData);

			// 解压缩
			if(_header.compressionMethod == CompressionMethod.UNCOMPRESSED ){

			}else if(_header.compressionMethod == CompressionMethod.DEFLATE){
				_lastData.uncompress();
			}else if(_header.compressionMethod == CompressionMethod.LZMA){
				_lastData.uncompress("lzma");
			}		
		}
		private function processChunks(document:Object):void {
			var i :uint;
			
			_documentVO = new BsonVO();
			for (var property:String in document) {
				var voCreator:Function = ClassManager.instance.getClassCreator(property);
				if (_document[property] is Array) {
					var parray:Array = new Array();
					var arr:Array = document[property] as Array;
					for(i = 0;i<arr.length;i++){
						parray.push(voCreator(arr[i]));
					}
					_documentVO[property] = parray;
				}else {
					_documentVO[property] = voCreator(document[property]);
				}
			}
			
			_arrTexture = _documentVO.hasOwnProperty("textures")?_documentVO["textures"]:null;
			if (_arrTexture != null) {
				var arrLoader:Array = new Array();
				for (i = 0; i < _arrTexture.length ;i++){
					if (_arrTexture[i] is TextureEmbed) {
						var embedTexture:TextureEmbed = _arrTexture[i] as TextureEmbed;
						arrLoader.push(new LoaderDeferred(_url + "/" + embedTexture.name, embedTexture.data));
					}else {
						var extraTexture:TextureExtra = _arrTexture[i] as TextureExtra;
						arrLoader.push(new LoaderDeferred(extraTexture.url));
					}
				}
				whenOneArray(arrLoader).completes(onTextureComplate).fails(onTextureFails);
			}
		}
		
		private function onTextureComplate(data:Array):void {
			_bitmapData = new Array(data.length);
			for (var i:int = 0; i < data.length;i++){
				_bitmapData[i] = LoaderDeferred(data[i]).data;
			}
			_texturesFinished = true;
		}
		private function onTextureFails(e:Error):void {
			error = e;
			_texturesFinished = true;
		}
		
		public function get documentVO():BsonVO 
		{
			return _documentVO;
		}
		
		public function get bitmapData():Array 
		{
			return _bitmapData;
		}
		
		public function get isDone():Boolean
		{
			return _parsedStep == ParserStep_Done;
		}
	}
}